using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using ZoneFiveSoftware.Common.Data;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Data.Measurement;
using FilteredStatistics.Common;
using FilteredStatistics.Common.Controller;
using FilteredStatistics.Controller;
using FilteredStatistics.View;

namespace FilteredStatistics.Data
{
    class CustomTimeLapsFilterCriteria : FilterCriteriaFacade, ISplitsCriteria
    {
        public CustomTimeLapsFilterCriteria(IActivity activity, TimeSpan duration)
        {
            m_ActivityCallbackHelper = new ActivityDataChangedHelper(activity);
            m_ActivityCallbackHelper.PropertyChanged += new PropertyChangedEventHandler(OnActivityDataChanged);

            Init(activity, duration);
        }

#region FilterCriteriaFacade members

        public override Guid ReferenceId
        {
            get { return GUIDs.SplitsCriteriaGuid; }
        }

        public override IActivity Activity
        {
            set
            {
                if (m_Activity != value)
                {
                    m_Activity = value;

                    CreateSplitsNamedZonesList();
                }
            }
        }

        public override string DisplayName
        {
            get { return PluginView.GetLocalizedString("CustomDistanceLapsText"); }
        }

        public override bool IsTemplateOnly
        {
            get { return false; }
        }

        public override bool IsMainViewOnly
        {
            get { return false; }
        }

        public override List<object> NamedZones
        {
            get { return m_SplitsNamedZones; }
        }

        public override bool IsSerializable
        {
            get { return false; }
        }

        public override UInt16 DataVersion
        {
            get { return Constants.CurrentVersion.VersionNumber; }
        }

        public override object DeserializeCriteria(Stream stream, UInt16 dataVersion)
        {
            Debug.Assert(false);

            return null;
        }

        public override void SerializeCriteria(Stream stream)
        {
            Debug.Assert(false);
        }

        public override object TemplateCompatibleCriteria
        {
            get
            {
                TimeSpan maxDuration = new TimeSpan(m_LapDuration.Ticks * NamedZones.Count);

                return new TemplateCustomTimeLapsFilterCriteria(maxDuration, m_LapDuration);
            }
        }

#endregion

#region ISplitsCriteria Members

        public SplitsCriteriaType SplitsType
        {
            get { return SplitsCriteriaType.CustomTime; }
        }

#endregion

#region IPluginSerializable members

        public override void Serialize(Stream stream)
        {
            // We should never end up with this in a template
            Debug.Assert(false);
        }

#endregion

        private void OnActivityDataChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Activity.Duration")
            {
                CreateSplitsNamedZonesList();
            }
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            CustomTimeLapsFilterCriteria criteria = obj as CustomTimeLapsFilterCriteria;
            SplitsPlaceholderFilterCriteria criteriaPlaceholder = obj as SplitsPlaceholderFilterCriteria;

            if (criteriaPlaceholder != null)
            {
                return true;
            }
            else if (criteria != null)
            {
                return criteria.LapTime == LapTime;
            }

            return base.Equals(obj);
        }

        private void CreateSplitsNamedZonesList()
        {
            if (m_Activity != null)
            {
                // Clear the cache because there's a refresh delay sometimes...
                ActivityInfo activityInfo = ActivityInfoCache.Instance.GetInfo(m_Activity);
                TimeSpan lapStartTime = new TimeSpan(0, 0, 0);
                TimeSpan lapEndTime = lapStartTime + m_LapDuration;
                TimeSpan activityActiveTime = Utils.GetActiveActivityTime(m_Activity);
                int lapIndex = 0;

                // Create/update a named zone for each distance interval
                while (lapStartTime < activityActiveTime)
                {
                    TimeLapNamedZone currentNamedZone;

                    lapEndTime = new TimeSpan(0, 0, (int)Math.Min(lapEndTime.TotalSeconds, Utils.GetActiveActivityTime(m_Activity).TotalSeconds));

                    if(m_SplitsNamedZones.Count > lapIndex)
                    {
                        // Reuse the already created named zone
                        currentNamedZone = m_SplitsNamedZones[lapIndex] as TimeLapNamedZone;
                        currentNamedZone.Init(m_Activity, lapStartTime, lapEndTime);
                    }
                    else
                    {
                        // Create a new one
                        currentNamedZone = new TimeLapNamedZone(m_Activity, lapIndex, lapStartTime, lapEndTime);
                        m_SplitsNamedZones.Add(currentNamedZone);
                    }

                    lapStartTime = lapEndTime;
                    lapEndTime += m_LapDuration;
                    lapIndex++;
                }

                // Remove excess named zones if required
                if (lapIndex < m_SplitsNamedZones.Count)
                {
                    m_SplitsNamedZones.RemoveRange(lapIndex, m_SplitsNamedZones.Count - lapIndex);
                }
            }

            TriggerNamedZonesListChanged();
        }

        public void Init(IActivity activity, TimeSpan duration)
        {
            m_LapDuration = duration;
            Activity = activity;
        }

        public TimeSpan LapTime
        {
            get { return m_LapDuration; }
        }

        private IActivity m_Activity = null;
        private ActivityDataChangedHelper m_ActivityCallbackHelper = null;
        private TimeSpan m_LapDuration;
        private List<object> m_SplitsNamedZones = new List<object>();
    }
}
